G = G or {};
G.dataTable =  G.dataTable or {}
local DTMgr = {
    fullJsonCacheList = {},
    fullJsonCacheListQueue = {},
    fullJsonCacheSaveNum = 200,--保存数量
    earliestIndex = 1,--最早插入的索引
}
setmetatable(G.dataTable,{__index = function(table,name)
    if table == nil or name == nil then
        return
    end
    local name = tostring(name)
    if rawget(table,name) == nil then
        local sTable = require("Data/"..name)
        local newTable = {}
        setMetatableConfigTable(name,sTable)
        --local keyTable = sTable["_key_"];
        local keyList = EnumConst.tableMultiId[name]
        for k,v in pairs(sTable) do
            if k ~= "_key_" then
                local t = v
                --setMetatableDecodeJsonStrToTable(t)
                local cache
                if keyList ~= nil then
                    if #keyList == 0 then
                        newTable[k] = t
                    else
                        for i,j in pairs(keyList) do
                            if cache == nil then
                                cache = newTable
                            end
                            if i == #keyList then
                                cache[t[j]] = t
                            else
                                if cache[t[j]] == nil then
                                    cache[t[j]] = {}
                                end
                                cache = cache[t[j]]
                            end
                        end
                    end

                else
                    newTable[tostring(k)] = t
                end
            end
        end
        rawset(table,name,newTable)
        for k,v in pairs(sTable) do
            sTable[k] = nil
        end
        package.loaded["data/"..name] = nil;
        _G["data/"..name] = nil
    end

    return rawget(table,name)
end})

--[[function setMetatableDecodeJsonStrToTabe(table)
    setmetatable(table,{__newindex = function(t,k,v)
        if v ~= nil then
            if type(v) == "string" then
                if string.sub(v,0,1) == "[" then
                    local tempV = decodeJsonStrToTabel(v)
                    if tempV ~= nil then
                        v = tempV
                    end
                end
            end 
        end
        rawset(t,k,v)
    end})
end]]
function setMetatableDecodeJsonStrToTable(table)
    setmetatable(table,{
        __newindex = function(t,k,v)
            if v ~= nil then
                if type(v) == "string" then
                    if string.byte(v,1,1) == 91 then --"["
                        local localMeta = rawget(t,"__localMeta")
                        if localMeta == nil then
                            localMeta = {}
                            rawset(t,"__localMeta",localMeta)
                        end
                        localMeta[k] = v
                        return
                    end
                end
            end
            rawset(t,k,v)
        end,
        __index = function(t,k)
            local localMeta = rawget(t,"__localMeta")
            if localMeta == nil then
                return nil
            end
            local v = rawget(localMeta,k)
            if v ~= nil then
                local tempV = DTMgr.Get(v)
                if tempV == nil then
                    tempV = decodeJsonStrToTabel(v)
                    if tempV ~= nil then
                        DTMgr.Insert(v,tempV)
                        return tempV
                    end
                else
                    return tempV
                end
            end
            return v
        end
    })
end
function setMetatableConfigTable(name,originTable)
    local keys = originTable["_key_"]
    local __keys = {}
    for k,v in pairs(keys) do
        __keys[v] = k
    end
    local meta = {
        __index = function(t,k)
            local ks =  rawget(t,"__keys")
            local index = ks[k]
            if index == nil then return nil end
            local value = t[index]
            if type(value) == "string" and string.byte(value,1,1) == 91 then --"["
                local tempV = DTMgr.Get(value)
                if tempV == nil then
                    tempV = decodeJsonStrToTabel(value)
                    if tempV ~= nil then
                        DTMgr.Insert(value,tempV)
                        return tempV
                    end
                else
                    return tempV
                end
            end
            return value
        end
    }
    local specialCfg = G.specialDataField1[name] --兼容老版本
    for k,v in pairs(originTable) do
        v["__keys"] = __keys
        if specialCfg then
            for _, key in ipairs(specialCfg) do
                local index = __keys[key]
                if index and not string.IsNilOrEmpty(v[index]) then
                    local newV = string.split(v[index], ",");
                    v[key] = newV
                end
            end
        end
        setmetatable(v,meta)
    end
end
function DTMgr.Insert(name,jsonTB)
    local this = DTMgr
    if #this.fullJsonCacheListQueue >= this.fullJsonCacheSaveNum then
        --print("Insert name "..name)
        local oldName = this.fullJsonCacheListQueue[this.earliestIndex]
        this.fullJsonCacheListQueue[this.earliestIndex] = name
        this.earliestIndex = (this.earliestIndex ) % this.fullJsonCacheSaveNum + 1
        this.fullJsonCacheList[oldName] = nil
        this.fullJsonCacheList[name] = jsonTB
    else
        table.insert(this.fullJsonCacheListQueue,name)
        this.fullJsonCacheList[name] = jsonTB
    end
end
function DTMgr.Get(name)
    return DTMgr.fullJsonCacheList[name]
end
G.dataKeyTable =  G.dataKeyTable or {}
dataTable = {}
local this = dataTable
local type = type;

--获取指定表格名称中的Key值(ps：需要进一步优化， 将cfgName定义成枚举)
function dataTable.getRow(tableName, key)
    if not tableName or not key then return nil end
	tableName = string.lower(tableName)
    local isOld = logicMgr.LoginManager.getIsServerOld()
    if isOld and G.dataTable["t_tablemap"][tableName] then
        local oldTableName = G.dataTable["t_tablemap"][tableName]["f_Table_old"]
        return G.dataTable[tostring(oldTableName)][tostring(key)]
    end
    return G.dataTable[tostring(tableName)][tostring(key)]
end

-- @function: sublime工具打印table的内容，递归
-- @param: tbl 要打印的table,tbl不是table不能打印
-- @param: level 递归的层数，默认不用传值进来
-- @param: filteDefault 是否过滤打印构造函数，默认为是
-- @return: return
function dataTable.PrintTable( tbl , level, filteDefault)
    local msg = ""
    filteDefault = filteDefault or true --默认过滤关键字（DeleteMe, _class_type）
    level = level or 1
    local indent_str = ""
    for i = 1, level do
        indent_str = indent_str.."  "
    end

    print(indent_str .. "{")
    for k,v in pairs(tbl) do
        if filteDefault then
            if k ~= "_class_type" and k ~= "DeleteMe" then
                local item_str = string.format("%s%s = %s", indent_str .. " ",tostring(k), tostring(v))
                print(item_str)
                if type(v) == "table" then
                    this.PrintTable(v, level + 1)
                end
            end
        else
            local item_str = string.format("%s%s = %s", indent_str .. " ",tostring(k), tostring(v))
            print(item_str)
            if type(v) == "table" then
                this.PrintTable(v, level + 1)
            end
        end
    end
    print(indent_str .. "}")
end

--- sublime工具打印table的内容，递归\
--- @param prefix string 前缀
--- @param tbl table 要打印的table,tbl不是table不能打印
--- @param level number 递归的层数，默认不用传值进来
--- @param filterDefault boolean 是否过滤打印构造函数，默认为是
function dataTable.PrintTableTogether(prefix, tbl, level, filterDefault)
    -- filterDefault = filterDefault or true --默认过滤关键字（DeleteMe, _class_type）
    -- level = level or 1
    -- local strList = { prefix }
    -- dataTable.PrintTableTogetherImpl(tbl, level, filterDefault, strList)
    --print(table.concat(strList, "\n"))
end

--- @private
function dataTable.PrintTableTogetherImpl(tbl, level, filterDefault, strList)
    local indent_str = ""
    for _ = 1, level do
        indent_str = indent_str .. "  "
    end

    table.insert(strList, indent_str .. "{")
    for k, v in pairs(tbl) do
        if filterDefault then
            if k ~= "_class_type" and k ~= "DeleteMe" then
                local item_str = string.format("%s%s = %s", indent_str .. " ", tostring(k), tostring(v))
                table.insert(strList, item_str)
                if type(v) == "table" then
                    this.PrintTableTogetherImpl(v, level + 1, nil, strList)
                end
            end
        else
            local item_str = string.format("%s%s = %s", indent_str .. " ", tostring(k), tostring(v))
            table.insert(strList, item_str)
            if type(v) == "table" then
                this.PrintTableTogetherImpl(v, level + 1, nil, strList)
            end
        end
    end
    table.insert(strList, indent_str .. "}")
end

local datatable_cache = {}
function dataTable.getDataTable( table_name )
    table_name = string.lower(table_name)
    local isOld = logicMgr.LoginManager.getIsServerOld()
    local ret = G.dataTable[table_name]
    if isOld and G.dataTable["t_tablemap"][table_name] then
        local oldTableName = G.dataTable["t_tablemap"][table_name]["f_Table_old"]
        ret = G.dataTable[oldTableName]
    end
    if ret then return ret end
end
--通过id获取配置表数据，如果传入columnName，直接获得该列对应的值，不传则返回整行数据
function dataTable.getDataTableById( table_name,id,columnName)

    local cfgs = dataTable.getDataTable(table_name)
    if cfgs then
        if columnName then
            local c = cfgs[tonumber(id)]
            if not c then return nil end
            return c[columnName]
        else
            return cfgs[tonumber(id)]
        end
    end
    return nil
end
function dataTable.getDataTableByMultiId( table_name,id1,id2,id3)
    local cfgs = dataTable.getDataTable(table_name)
    if cfgs then
        if id1 then
            local c = cfgs[id1]
            if id2 then
                if c then
                    local c2 = c[id2]
                    if id3 then
                        return c2[id3]
                    else
                        return c2
                    end
                else
                    return nil
                end
            else
                return c
            end
        else
            return cfgs
        end

    end
    return nil
end
--通过id获取配置表数据，如果传入columnName，直接获得该列对应的值，不传则返回整行数据
function dataTable.getDataTableByStringId( table_name,id,columnName)
    if string.IsEmpty(table_name) then
        logError("无效的表名 ,name is "..tostring(table_name))
        return nil
    end
    local cfgs = dataTable.getDataTable(table_name)
    if cfgs then
        if columnName then
            local c = cfgs[tostring(id)]
            if not c then return nil end
            return c[columnName]
        else
            return cfgs[tostring(id)]
        end
    end
    return nil
end
function dataTable.getGlobalInt(id)
    return dataTable.getDataTableByStringId("t_global",tostring(id),"f_int_value")
end
function dataTable.getGlobalString(id)
    return dataTable.getDataTableByStringId("t_global",tostring(id),"f_string_value")
end
--读取 宝石，药品，符文，杂物等，把他们放一起
function dataTable.loadPropTable()
    local _ptype = {804,807,700,600,800,10};
    local _data = {"Word","Mate","Rune","Gem","Misc","Potion"};
    propTable = {};
    for i, v in pairs(_data) do
        local t = G.dataTable[v];
        for i1, v1 in pairs(t) do
            v1.ptype = _ptype[i];
            if(v1.Qcolor == nil) then
                v1.Qcolor = 6;
                v1.color = 6;
            end
            propTable[i1] = v1;
        end
    end
end

--this.loadTable("Skill/SkillData","skillID")
--this.PrintTable(G.dataTable["SkillData"])

--split ,
G.specialDataField1 = {
    ["t_roleconfig"] = {"idleFree","idleBattle","walk","run","attack","laydown","repel","hurt","cast","dead","victory"},

    ["t_skillshow"] = {"f_SkillFResource",
                       "f_CenterFPosition",
                       "f_CenterBPosition",
                       "f_SkillFPosition",
                       "f_SkillBPosition",
                       "f_HitFPosition",
                       "f_HitBPosition",
                       "f_FlyFPosition",
                       "f_HitFPosition",},

    ["t_buffshow"] = {"f_BuffVEXPosition",
                      "f_BuffVEXPosition_caster",
                      "b_BuffVEXPosition",
                      "b_BuffVEXPosition_caster",},

    ["t_effect3"] = {"f_SkillFPosition",},
}

--json string
G.specialDataField2 = {
    ["t_hero"] = {"f_HeroSize",},
    ["t_roleconfig"] = {"nomalSkill",},
    ["t_skillshow"] = {"f_NextSkill","f_SkillCv", "f_HitShowValue", "f_SkillShowValue"},
    ["t_effect1"] = {"f_Color",},
}

function G.findDataField(tbl, keyName, dataFieldName)
    local dataFieldList = tbl[keyName];
    if dataFieldList then
        for _, v in ipairs(dataFieldList) do
            if dataFieldName == v then
                return true
            end
        end
    end

    return false
end

function G.processDataField(tblName, colName, rawV)
    local v = rawV;
    if G.findDataField(G.specialDataField1, tblName, colName) then
        if rawV ~= nil and rawV ~= "" then
            v = string.split(rawV, ",");
            return true,v
        end
    --[[elseif G.findDataField(G.specialDataField2, tblName, colName) then
        if rawV ~= nil and rawV ~= "" then
            v = decodeJsonStrToTabel(rawV);
            return true,v
        end
        --logMy('processDataField', tblName, colName, rawV, v);]]
    end

    --logMy('processDataField', tblName, colName, rawV, v);
    return false,v;
end



return dataTable;
